package com.iams.manage.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import java.util.stream.Collectors;
import com.iams.common.utils.DateUtils;
import com.iams.common.utils.SecurityUtils;
import com.iams.common.utils.uuid.UUID;
import com.iams.manage.domain.Archive;
import com.iams.manage.domain.workflow.dto.BorrowRecordDTO;
import com.iams.manage.mapper.ArchiveMapper;
import com.iams.manage.service.IMailService;
import com.iams.manage.service.impl.converter.BorrowRecordConverterImpl;
import com.iams.system.domain.SysPost;
import com.iams.system.domain.SysUserPost;
import com.iams.system.mapper.SysPostMapper;
import com.iams.system.mapper.SysUserMapper;
import com.iams.system.mapper.SysUserPostMapper;
import jakarta.mail.MessagingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.iams.manage.mapper.BorrowRecordMapper;
import com.iams.manage.domain.workflow.BorrowRecord;
import com.iams.manage.service.IBorrowRecordService;


import com.iams.activiti8.service.impl.WorkFlowStarterImpl;

import com.iams.manage.domain.UserGroups;
/**
 * 借阅记录Service业务层处理
 * 
 * @author LiuTao
 * @date 2025-04-07
 */
@Service
public class BorrowRecordServiceImpl implements IBorrowRecordService
{
    @Autowired
    private BorrowRecordMapper borrowRecordMapper;

    @Autowired
    private BorrowRecordConverterImpl borrowRecordConverterImpl;

    @Autowired
    private WorkFlowStarterImpl workFlowStarter;


    @Autowired
    private ArchiveMapper archiveMapper;


    @Autowired
    private SysUserMapper sysUserMapper;


    @Autowired
    private IMailService mailService;

    @Autowired
    private TaskListImpl taskList;

    @Autowired
    private SysUserPostMapper sysUserPostMapper;

    @Autowired
    private SysPostMapper sysPostMapper;


    /**
     * 查询借阅记录
     * 
     * @param id 借阅记录主键
     * @return 借阅记录
     */
    @Override
    public BorrowRecordDTO selectBorrowRecordById(Long id)
    {
        // 判断当前用户是否为（审核员、馆长）
        // 一般情况下自己查自己，其他情况下必须是管理员
        if(SecurityUtils.hasGroupPermission(SecurityUtils.getLoginUser(), UserGroups.ALL_GROUPS))
        {
            return borrowRecordConverterImpl.entityToDto(borrowRecordMapper.selectBorrowRecordById(id));
        }
        else
        {
            return borrowRecordConverterImpl.entityToDto(borrowRecordMapper.selectBorrowRecordById(SecurityUtils.getLoginUser().getUserId()));
        }
    }

    /**
     * 查询借阅记录列表
     * 
     * @param borrowRecord 借阅记录
     * @return 借阅记录
     */
    @Override
    public List<BorrowRecordDTO> selectBorrowRecordList(BorrowRecord borrowRecord)
    {
        // 判断当前用户是否为（审核员、馆长），并且  没有查询具体的人，那就null
        if(SecurityUtils.hasGroupPermission(SecurityUtils.getLoginUser(), UserGroups.ALL_GROUPS)&&  borrowRecord.getUserId()==null)
        {
            borrowRecord.setUserId(null);
        }
        // 不是那些岗位，ID为空，只能查自己的借阅记录
        else if (borrowRecord.getUserId()==null)
        {
            borrowRecord.setUserId(SecurityUtils.getLoginUser().getUserId());
        }
        List<BorrowRecord> borrowRecordList =  borrowRecordMapper.selectBorrowRecordList(borrowRecord);
        // 转换每个元素
        // 收集为列表
        return borrowRecordList.stream()
                .map(borrowRecordEntity -> borrowRecordConverterImpl.entityToDto(borrowRecordEntity))
                .collect( Collectors.toList());
    }


    /**
     * 查询已逾期的实体档案借阅记录列表，需要设定状态：已逾期
     *
     * @param borrowRecord 借阅记录
     * @return 借阅记录
     */
    @Override
    public List<BorrowRecordDTO> selectOverdueBorrowRecordList(BorrowRecord borrowRecord)
    {
        borrowRecord.setStatus("已逾期");
        return selectBorrowRecordList(borrowRecord);
    }

    /**
     * 新增借阅记录
     * 
     * @param borrowRecordDTO 借阅记录
     * @return 结果
     */
    @Override
    public int insertBorrowRecord(BorrowRecordDTO borrowRecordDTO)
    {
        // 以下代码做成验证器似乎有些麻烦，要些四个验证器，不如在这里做了。
        // 档案验证注解：是否存在、状态不是销毁，那就可以借阅
        // 记录表中不能重复借阅：用户ID-档案ID-借阅状态（已批准）
        List<BorrowRecord> borrowRecordList = borrowRecordMapper.selectBorrowRecordList(new BorrowRecord(borrowRecordDTO.getUserId(), borrowRecordDTO.getArchiveId()));
        for(BorrowRecord borrowRecord : borrowRecordList)
        {
            if(borrowRecord.getStatus().equals("已批准"))
            {
                throw new RuntimeException("该档案已被借阅，请勿重复借阅");
            }
            else if(borrowRecord.getStatus().contains("审批"))
            {
                throw new RuntimeException("请勿重复发起申请");
            }
        }
        // 传入DTO，转换成实体
        BorrowRecord borrowRecord = borrowRecordConverterImpl.dtoToEntity(borrowRecordDTO);
        borrowRecord.setBusinessKey(UUID.randomUUID().toString());


        String instanceId = workFlowStarter.startProcessInstanceByDefinitionKey(borrowRecord.getProcessName(), borrowRecord.getBusinessKey(), borrowRecordDTO.getUserName()+"借阅申请");

        borrowRecord.setInstanceId(instanceId);
        borrowRecord.setStartApplyTime(DateUtils.getNowDate());
        borrowRecord.setStatus("待审批");
        return borrowRecordMapper.insertBorrowRecord(borrowRecord);
    }

    /**
     * 修改借阅记录
     * 
     * @param borrowRecordDTO 借阅记录
     * @return 结果
     */
    @Override
    public int updateBorrowRecord(BorrowRecordDTO borrowRecordDTO)
    {
        BorrowRecord borrowRecord = borrowRecordConverterImpl.dtoToEntity(borrowRecordDTO);
        if(borrowRecordMapper.selectBorrowRecordById(borrowRecord.getId()).getStatus().equals("已批准")
        || borrowRecordMapper.selectBorrowRecordById(borrowRecord.getId()).getStatus().equals("已驳回")
        || borrowRecordMapper.selectBorrowRecordById(borrowRecord.getId()).getStatus().equals("已结束"))
        {
            throw new RuntimeException("流程已结束，无法修改");
        }
        return borrowRecordMapper.updateBorrowRecord(borrowRecord);
    }


    @Override
    public int updateOverdueBorrowRecord(BorrowRecordDTO borrowRecordDTO){
        BorrowRecord borrowRecord = borrowRecordMapper.selectBorrowRecordById(borrowRecordDTO.getId());
        borrowRecord.setReturnDate(DateUtils.getNowDate());
        borrowRecord.setStatus("已结束");
        return borrowRecordMapper.updateBorrowRecord(borrowRecord);
    }

    @Override
    public void updateBorrowRecord(BorrowRecord borrowRecord)
    {
        borrowRecordMapper.updateBorrowRecord(borrowRecord);
    }

    /**
     * 批量删除借阅记录
     * 
     * @param ids 需要删除的借阅记录主键
     * @return 结果
     */
    @Override
    public int deleteBorrowRecordByIds(Long[] ids)
    {
        for (Long id : ids)
            deleteBorrowRecordById(id);

        return 1;
    }

    /**
     * 删除借阅记录信息
     * 
     * @param id 借阅记录主键
     * @return 结果
     */
    @Override
    public int deleteBorrowRecordById(Long id)
    {
        workFlowStarter.deleteProcessInstance(borrowRecordMapper.selectBorrowRecordById(id).getInstanceId());
        return borrowRecordMapper.deleteBorrowRecordById(id);
    }

    @Override
    public BorrowRecord selectBorrowRecordByBusinessKey(String businessKey)
    {
        return borrowRecordMapper.selectBorrowRecordByBusinessKey(businessKey);
    }

    @Override
    @Scheduled(cron = "0 0 0 * * ?")
    public void borrowRecordStatus() {
        BorrowRecord borrowRecord = new BorrowRecord();
        borrowRecord.setStatus("已批准");

        borrowRecordMapper.selectBorrowRecordList(borrowRecord).forEach(record -> {
            Date endDate = record.getEndDate();

            if (endDate != null && endDate.getTime() < System.currentTimeMillis()) {
                // 只查询一次
                Archive archive = archiveMapper.selectArchiveById(record.getArchiveId());
                if (archive != null) {
                    String carrierType = archive.getCarrierType();
                    long diffInMillis = System.currentTimeMillis() - endDate.getTime(); // 计算毫秒差值
                    long overdueDays = diffInMillis / (1000 * 60 * 60 * 24); // 转换为天数

                    if ("Mixture".equals(carrierType) || "tangible".equals(carrierType)) {
                        record.setStatus("已逾期");
                        record.setOverdueDays(overdueDays);
                    } else {
                        record.setStatus("已结束");
                    }

                    borrowRecordMapper.updateBorrowRecord(record);
                }
            }
        });
    }

    @Override
    public int reminder(BorrowRecordDTO borrowRecordDTO)
    {
        BorrowRecord borrowRecord = borrowRecordMapper.selectBorrowRecordById(borrowRecordDTO.getId());
        String mail = sysUserMapper.selectUserById(borrowRecord.getUserId()).getEmail();
        try{
            mailService.sendHtmlMail(mail, "借阅逾期提醒", "借阅申请已过期，请及时处理！", true);

        }catch (MessagingException e){
            return 0;
        }

        return 1;
    }

    /**
     * 催办，我们需要提前检验是否可以被催办，催办通过 业务键查找对应的任务组或者任务候选人，根据用户信息发送催办信息
     * @param id
     * @return
     */
    @Override
    public int expedite(Long id)
    {
        BorrowRecord borrowRecord = borrowRecordMapper.selectBorrowRecordById(id);
        if(!borrowRecord.getStatus().contains("审批") )
        {
            throw new RuntimeException("流程已结束，无法催办");
        }
        String businessKey = borrowRecord.getBusinessKey();

        // 候选组可能会有很多岗位多个（但是没有测试在流程中是否能正常工作）
        List<String> result = taskList.getCandidateUsers(businessKey);

        List<SysUserPost> userPostList = new ArrayList<>();

        // 根据岗位CODE查找ID ，根据ID查找用户ID，每个岗位下面也会有多个用户
        result.forEach(userPost -> {

            List<SysPost> sysPosts = sysPostMapper.selectPostList(new SysPost(userPost));

            // 找到ID
            Long postID = sysPosts.get(0).getPostId();

            // 根据岗位ID查找用户
            userPostList.addAll(sysUserPostMapper.selectUserIdByPostCode(postID));

        });
        userPostList.forEach(userPost -> {
            System.out.println(userPost.getUserId());
        });


        return 1;
    }


    @Override
    public int advanceReturn(Long Id)
    {
        BorrowRecord borrowRecord = borrowRecordMapper.selectBorrowRecordById(Id);
        borrowRecord.setStatus("已结束");
        borrowRecord.setReturnDate(DateUtils.getNowDate());
        borrowRecordMapper.updateBorrowRecord(borrowRecord);

        return 1;
    }

    private void rfidReturn(String Rfid)
    {
        Long archiveId = archiveMapper.getArchiveIdByRfid(Rfid);
        if (archiveId != null){

            BorrowRecord borrowRecord = borrowRecordMapper.selectBorrowRecordByArchiveId(archiveId);
            if (borrowRecord != null){
                borrowRecord.setStatus("已结束");
                borrowRecord.setReturnDate(DateUtils.getNowDate());
                borrowRecordMapper.updateBorrowRecord(borrowRecord);
            }
        }
    }
}
